# -*- python -*-
# ex: set syntax=python:

# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# It has one job: define a dictionary named BuildmasterConfig. This
# dictionary has a variety of keys to control different aspects of the
# buildmaster. They are documented in docs/config.xhtml .

from buildbot.scheduler import Dependent
from buildbot.scheduler import Scheduler
from buildbot.scheduler import Periodic
from buildbot.schedulers import triggerable
from buildbot.steps import trigger

from common import chromium_utils
from master import build_utils
from master import master_utils
from master import slaves_list
from master.factory import gclient_factory, annotator_factory
from master.factory.dart import dart_factory
from master.factory.dart.dart_factory import (linux_env, windows_env,
                                              linux_clang_env)
from master.factory.dart.channels import CHANNELS

import config
import master_site_config
ActiveMaster = master_site_config.DartFYI
utils = dart_factory.DartUtils(ActiveMaster)

# Hack to increase timeout for steps, dart2js debug checked mode takes more
# than 8 hours.
utils.monkey_patch_remoteshell()

MASTER_HOST = ActiveMaster.master_host
WEB_STATUS = True
MAIL_NOTIFIER = ActiveMaster.is_production_host

# This is the dictionary that the buildmaster pays attention to. We also use
# a shorter alias to save typing.
c = BuildmasterConfig = {}

config.DatabaseSetup(c, require_dbconfig=ActiveMaster.is_production_host)

# 'slavePortnum' defines the TCP port to listen on. This must match the value
# configured into the buildslaves (with their --master option)
c['slavePortnum'] = ActiveMaster.slave_port

slaves = slaves_list.SlavesList('slaves.cfg', 'DartFYI')

m_annotator = annotator_factory.AnnotatorFactory()

def setup_channel(channel):
  postfix = channel.builder_postfix

  ####### Variant definitions
  # build-base-name, category, platform, builder, tester
  # env are relative to the dart root directory.

  def category(name):
    return '%d%s%s|all' % (channel.position, name, channel.category_postfix)

  variants = [
    {
      'name': 'dart2js-dump-info' + postfix,
      'category': category('20dart2js'),
      'platform': 'posix' + postfix,
      'env': linux_env,
    },
    {
      'name': 'dart2js-linux-release-cps' + postfix,
      'category': category('2dart2js'),
      'platform': 'posix' + postfix,
      'env': linux_env,
    },
    {
      'name': 'dart2js-chromeOnAndroid-linux' + postfix,
      'category': category('2dart2js'),
      'platform': 'chromeOnAndroid' + postfix,
      'env': linux_env,
    },
    {
      'name': 'dart2js-linux-debug' + postfix,
      'category': category('2dart2js'),
      'platform': 'posix' + postfix,
      'env': linux_env,
    },
    {
      'name': 'dart2js-linux-debug-checked' + postfix,
      'category': category('2dart2js'),
      'platform': 'posix' + postfix,
      'env': linux_env,
    },
    {
      'name': 'dart2js-linux-debug-host-checked' + postfix,
      'category': category('2dart2js'),
      'platform': 'posix' + postfix,
      'env': linux_env,
    },
    {
      'name': 'dart2js-linux-debug-checked-host-checked' + postfix,
      'category': category('2dart2js'),
      'platform': 'posix' + postfix,
      'env': linux_env,
    },
    {
      'name': 'dart2js-linux-release-host-checked' + postfix,
      'category': category('2dart2js'),
      'platform': 'posix' + postfix,
      'env': linux_env,
    },
    {
      'name': 'dart2js-linux-release' + postfix,
      'category': category('2dart2js'),
      'platform': 'posix' + postfix,
      'env': linux_env,
    },
    {
      'name': 'dart2js-linux-release-checked-host-checked' + postfix,
      'category': category('2dart2js'),
      'platform': 'posix' + postfix,
      'env': linux_env,
    },
    {
      'name': 'dart2js-linux-release-checked-host-checked-x64' + postfix,
      'category': category('2dart2js'),
      'platform': 'posix' + postfix,
      'env': linux_env,
    },
    {
      'name': 'dart2js-full-windows-1-6' + postfix,
      'category': category('91dart2js-win'),
      'platform': 'windows' + postfix,
      'env': windows_env,
    },
    {
      'name': 'vm-android-linux' + postfix,
      'category': category('8android'),
      'platform': 'android' + postfix,
      'env': linux_env,
    },
    {
      'name': 'dart2js-chrome-linux' + postfix,
      'category': category('90chrome'),
      'platform': 'posix' + postfix,
    },
    {
      'name': 'vm-mips-debug' + postfix,
      'category': category('1vm'),
      'platform': 'posix' + postfix,
      'mode': 'debug',
      'arch': 'mips',
      'env': linux_env,
    },
    {
      'name': 'vm-mips-release' + postfix,
      'category': category('1vm'),
      'platform': 'posix' + postfix,
      'mode': 'release',
      'arch': 'mips',
      'env': linux_env,
    },
  ]

  variants_v8 = [
    {
      'name': 'v8-linux-release',
      'factory_builder': m_annotator.BaseFactory('v8'),
      'category': category('3v8'),
      'platform': 'v8_vm',
      'arch': 'ia32',
    },
    {
      'name': 'v8-win-release',
      'factory_builder': m_annotator.BaseFactory('v8'),
      'category': category('3v8'),
      'platform': 'v8_vm',
      'arch': 'ia32',
    },
    {
      'name': 'v8-mac-release',
      'factory_builder': m_annotator.BaseFactory('v8'),
      'category': category('3v8'),
      'platform': 'v8_vm',
      'arch': 'ia32',
    },
  ]

  variants_dartium = [
    {
      'name' : 'dartium-mac-debug' + postfix,
      'category' : category('96dartium-debug'),
    },
    {
      'name' : 'dartium-lucid64-debug' + postfix,
      'category' : category('96dartium-debug'),
    },
    {
      'name' : 'dartium-win-debug' + postfix,
      'category' : category('96dartium-debug'),
    },
  ]

  variants_ft = [
    {
      'name': 'ft-slave-linux' + postfix,
      'category': category('4dart-editor'),
      'platform': 'posix' + postfix,
    },
    {
      'name': 'ft-slave-mac' + postfix,
      'category': category('4dart-editor'),
      'platform': 'posix' + postfix,
    }
  ]


  variants_ft_master = [
    {
      'name': 'ft-master' + postfix,
      'category': category('4dart-editor'),
      'platform': 'posix' + postfix,
      'triggers' : [{
        'schedulerNames': ['ft-slaves' + postfix],
        'waitForFinish': True,
        'updateSourceStamp': False,
      }],
      'second_annotated_steps_run' : True,
    },
  ]


  ####### Dartium integration overrides, we only use the dartium builders there
  if channel.name == 'integration':
    variants = []
    variants_ft = []
    variants_ft_master = []
    variants_editor_linux = []
    variants_editor_mac = []
    variants_editor_win = []
    variants_editor_installer = []
    variants_arm = []

  # Additional builders, only on the bleeding-edge channel.
  def dartium_factory(action, product, platform, triggers):
    perf_platform = 'windows' if platform == 'win' else platform
    factory_properties = {
      'deps': '%s.deps' % product,
      'target': 'Release',
      'internal': True,
      'perf_id': '%s-%s-release' % (product, perf_platform),
      'USE_MIRROR': ActiveMaster.is_production_host,
    }
    if platform == 'mac':
      factory_properties['reference_build_executable'] = (
          'src/chrome/tools/test/reference_build/chrome_mac/'
          'Chromium.app/Contents/MacOS/Chromium')
    return m_annotator.BaseFactory(
        recipe='dart/dartium_%s' % action,
        factory_properties=factory_properties,
        triggers=triggers)

  perf_builders = []
  if channel.name == 'be':
    for action in ('build', 'perf'):
      for platform in ('linux', 'mac', 'win'):
        for product in ('dartium', 'multivm') :
          name = '%s-%s-%s-%s' % (product, platform, action, channel.name)
          trigger_name = 'fyi-perf-%s-%s-%s' % (product, platform, channel.name)
          triggers = [trigger_name] if action == 'build' else []
          builder = {
              'name': name,
              'builddir': name,
              'category': category('5%s' % product),
              'factory': dartium_factory(action, product, platform, triggers),
              'auto_reboot': True,
          }
          perf_builders.append(builder)

  ####### Factory setup

  utils.setup_factories(variants)
  utils.setup_factories(variants_ft)
  utils.setup_factories(variants_ft_master)
  utils.setup_dartium_factories(variants_dartium)

  ####### Schedulers

  builder_names = utils.get_builder_names(variants)

  builder_names_ft = utils.get_builder_names(variants_ft)

  perf_builder_names = [builder['name'] for builder in perf_builders
                            if '-build-' in builder['name']]
  perf_tester_names = [builder['name'] for builder in perf_builders
                            if '-perf-' in builder['name']]

  dartium_builder_names = utils.get_builder_names(variants_dartium)


  c['schedulers'].append(triggerable.Triggerable(
      name='ft-slaves' + postfix,
      builderNames=builder_names_ft,
  ))

  # normal builders + editor builders + dartium builders
  c['schedulers'].append(Scheduler(
    name='fyi-main' + postfix,
    branch=channel.branch,
    treeStableTimer=0,
    builderNames=(builder_names + dartium_builder_names + perf_builder_names),
  ))

  if channel.name == 'be':
    # dartium and multivm performance testers
    for platform in ('linux', 'mac', 'win'):
      for product in ('dartium', 'multivm') :
        c['schedulers'].append(triggerable.Triggerable(
            name='fyi-perf-%s-%s-%s' % (product, platform, channel.name),
            builderNames=[tester for tester in perf_tester_names
                          if platform in tester and product in tester],
        ))

  ####### Builders

  # Add non-dartium builders
  for collection in [variants, variants_ft, variants_ft_master]:
    for b in utils.get_builders_from_variants(collection, slaves, []):
      c['builders'].append(b)

  # Add dartium builders
  for collection in [variants_dartium]:
    # Reboot VMs after every build
    for b in utils.get_builders_from_variants(collection, slaves, [],
                                              ActiveMaster.is_production_host):
      c['builders'].append(b)

  # v8
  if channel.name == 'be':
    # Add non-dartium builders
    for collection in [variants_v8]:
      for b in utils.get_builders_from_variants(collection, slaves, []):
        c['builders'].append(b)

  # Add perf builders
  for builder in perf_builders:
    builder['slavenames'] = slaves.GetSlavesName(builder=builder['name'])
    c['builders'].append(builder)

c['builders'] = []
c['schedulers'] = []
for channel in CHANNELS:
  setup_channel(channel)

####### CHANGESOURCES

c['change_source'] = [
    utils.get_svn_poller(),
    utils.get_github_poller('dart-lang', 'sdk', master='fyi'),
    utils.get_github_poller('dart-lang', 'sdk', branch='dev', master='fyi')]

####### BUILDSLAVES

c['slaves'] = utils.get_slaves(c['builders'])

# Make sure everything works together.
master_utils.VerifySetup(c, slaves)

# Prioritize the builders depending on channel.
c['prioritizeBuilders'] = utils.prioritize_builders


####### STATUS TARGETS

# 'status' is a list of Status Targets. The results of each build will be
# pushed to these targets. buildbot/status/*.py has a variety to choose from,
# including web pages, email senders, and IRC bots.

c['status'] = []

if WEB_STATUS:
  for status in utils.get_web_statuses():
    c['status'].append(status)

if MAIL_NOTIFIER:
  # We have people that are interested in a specific subset of the builders
  # and want to be notified whenever they break.
  mail_notifiers = [
    {
      'extraRecipients' : ['ricow@google.com',
                           'johnniwinther@google.com',
                           'karlklose@google.com',
                           'floitsch@google.com'],
      'builders' : ['dart2js-linux-debug',
                    'dart2js-linux-debug-checked',
                    'dart2js-linux-debug-host-checked',
                    'dart2js-linux-debug-checked-host_checked',
                    'dart2js-linux-release-host-checked',
                    'dart2js-linux-release-checked-host-checked'],
    },
    {
      'extraRecipients' : ['ricow@google.com',
                           'erikcorry@google.com'],
      'builders' : ['dart2js-linux-release-host-checked-minified'],
    },
    {
      'extraRecipients' : ['kmillikin@google.com',
                           'karlklose@google.com',
                           'asgerf@google.com'],
      'builders' : ['dart2js-linux-release-cps-be',
                    'dart2js-linux-release-cps-dev',
                    'dart2js-linux-release-cps-stable'],
      'subject' : 'Dart2dart backend compiler broke',
    },
    {
      'extraRecipients' : ['zra@google.com',
                           'whesse@google.com',
                           'ricow@google.com'],
      'builders' : ['dartium-android-builder'],
      'subject' : 'Dartium android content-shell builder broke',
    }
  ]

  for notifier in utils.get_mail_notifier_statuses(mail_notifiers):
    c['status'].append(notifier)


# Keep last build logs, the default is too low.
c['buildHorizon'] = 1000
c['logHorizon'] = 500
# Must be at least 2x the number of slaves.
c['eventHorizon'] = 200
# Must be at least 1x the number of builds listed in console.
c['buildCacheSize'] = 60

c['properties'] = {'mastername': master_utils.GetMastername()}

####### PROJECT IDENTITY

# the 'projectName' string will be used to describe the project that this
# buildbot is working on. For example, it is used as the title of the
# waterfall HTML page. The 'projectURL' string will be used to provide a link
# from buildbot HTML pages to your project's home page.

c['projectName'] = ActiveMaster.project_name
c['projectURL'] = config.Master.project_url

# the 'buildbotURL' string should point to the location where the buildbot's
# internal web server (usually the html.Waterfall page) is visible. This
# typically uses the port number set in the Waterfall 'status' entry, but
# with an externally-visible host name which the buildbot cannot figure out
# without some help.

c['buildbotURL'] = ActiveMaster.buildbot_url
